function RKTree = ConstructRKTree( N, nLevel, SampleList )

DIRECT = 1;
INDIRECT = 0;

RKTree = cell(nLevel,1);
nWidthTop = N / 4;

for iLevel = 1 : nLevel
  if( iLevel == 1 )
    nWidth = nWidthTop;
    nBlockCur = 4;
  else
    nWidth = nWidth / 2;
    nBlockCur = nBlockCur * 2;
  end
  nSourceCur = SampleList{iLevel}.nSource;
  nTargetCur = SampleList{iLevel}.nTarget;
  nRKBlockCur = nSourceCur * nTargetCur / 2;

  % Each element of RKSource is a 2 by 2 matrix recording the position
  % (in 2-d domain) of the source; Similarly for RKTarget
  
  RKTree{iLevel} = struct('nWidth', nWidth, ...
    'nBlock', nBlockCur, 'nRKBlock', nRKBlockCur, ...
    'RKSource', [], 'RKTarget', [], ...
    'RKSourceInd', [], 'RKTargetInd', [], ...
    'RKBlockU', [], 'RKBlockV', [], ...
    'RKBlockUniU', [], ...
    'RKBlockUniM', [], ...
    'RKBlockM', [], ...
    'RKBlockSDIRECT', [], ...
    'RKBlockSINDIRECT', [] );

  RKTree{iLevel}.RKSource = zeros( 2, 2, RKTree{iLevel}.nRKBlock );
  RKTree{iLevel}.RKTarget = zeros( 2, 2, RKTree{iLevel}.nRKBlock );
  RKTree{iLevel}.RKSourceInd = zeros( RKTree{iLevel}.nRKBlock, 1 );
  RKTree{iLevel}.RKTargetInd = zeros( RKTree{iLevel}.nRKBlock, 1 );
  RKTree{iLevel}.RKBlockU = cell(nRKBlockCur, 1);
  RKTree{iLevel}.RKBlockV = cell(nRKBlockCur, 1);
  RKTree{iLevel}.RKBlockUniU = cell(nSourceCur, 1);
  RKTree{iLevel}.RKBlockM = cell(nRKBlockCur, 1);
  RKTree{iLevel}.RKBlockUniM = cell(nRKBlockCur, 1);
  RKTree{iLevel}.RKBlockSDIRECT = cell(nRKBlockCur, 1);
  RKTree{iLevel}.RKBlockSINDIRECT = cell(nRKBlockCur, 1);
  
  for iSource = 1 : SampleList{iLevel}.nSource
    for iTarget = 1 : SampleList{iLevel}.nTarget
      if( SampleList{iLevel}.SymFlag( iTarget, iSource ) == ...
	  DIRECT )
	Source = SampleList{iLevel}.Source(:, iSource);
	Target = SampleList{iLevel}.SourceTarget(:, iTarget, iSource );
	RKTree{iLevel}.RKSourceInd(SampleList{iLevel}.RKIndex(...
	  iTarget, iSource )) = iSource;
	RKTree{iLevel}.RKTargetInd(SampleList{iLevel}.RKIndex(...
	  iTarget, iSource )) = ...
	  SampleList{iLevel}.SourceTargetInd(iTarget, iSource);
	% The following 2*2 matrix is organized as
	% [ y_0 y_1 ]
	% [ x_0 x_1 ]
	RKTree{iLevel}.RKSource( :, :, SampleList{iLevel}.RKIndex(...
	  iTarget, iSource ) ) = ...
	  [ 1+(Source(1)-1)*RKTree{iLevel}.nWidth, ...
	    Source(1)*RKTree{iLevel}.nWidth; 
	    1+(Source(2)-1)*RKTree{iLevel}.nWidth, ...
	    Source(2)*RKTree{iLevel}.nWidth ];
	RKTree{iLevel}.RKTarget( :, :, SampleList{iLevel}.RKIndex(...
	  iTarget, iSource ) ) = ...
	  [ 1+(Target(1)-1)*RKTree{iLevel}.nWidth, ...
	    Target(1)*RKTree{iLevel}.nWidth; 
	    1+(Target(2)-1)*RKTree{iLevel}.nWidth, ...
	    Target(2)*RKTree{iLevel}.nWidth;
	  ];
      end
    end
  end
end
